package com.dlc.shop.sys.common.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.bean.enums.PositionType;
import com.dlc.shop.common.bean.LangConfig;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.i18n.I18nMessage;
import com.dlc.shop.manager.impl.LangManager;
import com.dlc.shop.sys.common.constant.MenuType;
import com.dlc.shop.sys.common.dao.ShopEmployeeMapper;
import com.dlc.shop.sys.common.dao.ShopMenuLangMapper;
import com.dlc.shop.sys.common.dao.ShopMenuMapper;
import com.dlc.shop.sys.common.dao.ShopRoleMenuMapper;
import com.dlc.shop.sys.common.model.ShopEmployee;
import com.dlc.shop.sys.common.model.ShopMenu;
import com.dlc.shop.sys.common.model.ShopMenuLang;
import com.dlc.shop.sys.common.service.ShopMenuService;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单管理
 * @author yami
 * @date 2021-03-01 17:42:09
 */
@Service
@AllArgsConstructor
public class ShopMenuServiceImpl extends ServiceImpl<ShopMenuMapper, ShopMenu> implements ShopMenuService {

    private final ShopMenuMapper shopMenuMapper;
    private final ShopRoleMenuMapper shopRoleMenuMapper;
    private final ShopEmployeeMapper shopEmployeeMapper;
    private final ShopMenuLangMapper shopMenuLangMapper;
    private final LangManager langManager;

    @Override
    public List<ShopMenu> listMenuAndBtn(Long employeeId) {
        ShopEmployee shopEmployee = shopEmployeeMapper.selectById(employeeId);
        List<ShopMenu> list;
        if (Objects.equals(PositionType.ADMIN.value(),shopEmployee.getType())){
            list = shopMenuMapper.listMenuAndBtn();
        }else {
            list = shopMenuMapper.listRoleMenuAndBtn(employeeId);
        }
        this.handleMenuLang(list);
        return list;
    }

    @Override
    public List<ShopMenu> listAllMenuAndBtn() {
        List<ShopMenu> list = shopMenuMapper.listMenuAndBtn();
        this.handleMenuLang(list);
        return list;
    }

    @Override
    public List<ShopMenu> listSimpleMenuNoButton() {
        List<ShopMenu> shopMenus = shopMenuMapper.listMenu();
        this.handleMenuLang(shopMenus);
        return shopMenus;
    }

    @Override
    public List<ShopMenu> listRootMenu() {
        List<ShopMenu> shopMenus = shopMenuMapper.listRootMenu();
        this.handleMenuLang(shopMenus);
        return shopMenus;
    }

    @Override
    public List<ShopMenu> listChildrenMenuByParentId(Long parentId) {
        List<ShopMenu> shopMenus = shopMenuMapper.listChildrenMenuByParentId(parentId);
        this.handleMenuLang(shopMenus);
        return shopMenus;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMenuAndRoleMenu(Long menuId) {
        // 删除菜单
        this.removeById(menuId);
        // 删除菜单与角色关联
        shopRoleMenuMapper.deleteByMenuId(menuId);
        // 删除菜单语言数据
        shopMenuLangMapper.deleteByMenuId(menuId);
    }

    @Override
    public List<ShopMenu> listMenuByEmployeeId(Long employeeId) {
        // 用户的所有菜单信息
        List<ShopMenu> shopMenus;
        //商铺超级管理员，拥有最高权限
        ShopEmployee shopEmployee = shopEmployeeMapper.selectById(employeeId);
        if(Objects.equals(PositionType.ADMIN.value(),shopEmployee.getType())){
            shopMenus = shopMenuMapper.listMenu();
        }else {
            shopMenus = shopMenuMapper.listMenuByEmployeeId(employeeId);
        }
        this.handleMenuLang(shopMenus);
        //List<ShopMenu> rootMenu = getTree(shopMenus, 0l);
        Map<Long, List<ShopMenu>> sysMenuLevelMap = shopMenus.stream().sorted(Comparator.comparing(ShopMenu::getOrderNum))
                .collect(Collectors.groupingBy(ShopMenu::getParentId));

        // 一级菜单
        List<ShopMenu> rootMenu = sysMenuLevelMap.get(0L);
        if (CollectionUtil.isEmpty(rootMenu)) {
            return Collections.emptyList();
        }
        // 二三级菜单
        for (ShopMenu sysMenu : rootMenu) {
            List<ShopMenu> secondList = sysMenuLevelMap.get(sysMenu.getMenuId());
            if (CollectionUtil.isEmpty(secondList)){
                sysMenu.setList(secondList);
                continue;
            }
            for (ShopMenu secondMenu : secondList) {
                secondMenu.setList(sysMenuLevelMap.get(secondMenu.getMenuId()));
            }
            sysMenu.setList(secondList);
        }
        return rootMenu;
    }

    public List<ShopMenu> getTree(List<ShopMenu> sysMenus, Long id){
        List<ShopMenu> list = new ArrayList<>();
        for (ShopMenu shopMenu : sysMenus) {
            if (shopMenu.getParentId().equals(id)) {
                list.add(shopMenu);
            }
        }
        //递归
        for (ShopMenu shopMenu  : list) {
            shopMenu.setList(getTree(sysMenus, shopMenu.getMenuId()));
        }
        if (list.size() == 0) {
            return null;
        }
        return list;
    }

    @Override
    public List<Long> listMenuIdByRoleId(Long roleId) {
        return shopMenuMapper.listMenuIdByRoleId(roleId);
    }

    @Override
    public Set<String> updateSonMenuState(Long parentId, Integer state) {
        shopMenuMapper.updateSonMenuState(parentId,state);
        return shopMenuMapper.listMenuPerms(parentId);
    }

    @Override
    public Set<String> listConcealButtonPerms() {
        return shopMenuMapper.listConcealButtonPerms();
    }

    @Override
    @Cacheable(cacheNames = "ShopPermissions", key = "#employeeId")
    public Set<String> getShopPermissions(Long employeeId, Boolean isAdmin) {
        List<String> permsList;

        //店铺超级管理员，拥有最高权限
        if(isAdmin){
            List<ShopMenu> menuList = shopMenuMapper.selectList(Wrappers.emptyWrapper());
            permsList = menuList.stream().map(ShopMenu::getPerms).collect(Collectors.toList());
        }else{
            permsList = shopEmployeeMapper.queryAllPerms(employeeId);
        }

        return permsList.stream().flatMap((perms)->{
            if (StrUtil.isBlank(perms)) {
                return null;
            }
            return Arrays.stream(perms.trim().split(StrUtil.COMMA));
        }).collect(Collectors.toSet());
    }

    @Override
    public List<String> listMenuNameByPerms(String perms) {
        List<ShopMenu> shopMenuList = shopMenuMapper.listMenuNameByPerms(perms);
        if (CollUtil.isEmpty(shopMenuList)) {
            return new ArrayList<>();
        }
        handleMenuLang(shopMenuList);
        List<String> list = shopMenuList.stream().map(ShopMenu::getName).filter(name -> Objects.nonNull(name)).collect(Collectors.toList());
        return list;
    }

    @Override
    public ShopMenu getShopMenu(Long menuId) {
        ShopMenu shopMenu = shopMenuMapper.getShopMenuByMenuId(menuId);
        this.handleMenuAndLang(Collections.singletonList(shopMenu));
        return shopMenu;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveShopMenu(ShopMenu shopMenu) {
        //数据校验
        verifyForm(shopMenu);
        save(shopMenu);
        // 保存菜单语言列表
        batchSaveMenuLang(shopMenu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateShopMenu(ShopMenu shopMenu) {
        //数据校验
        verifyForm(shopMenu);
        updateById(shopMenu);
        // 先删除再保存菜单语言列表
        shopMenuLangMapper.deleteByMenuId(shopMenu.getMenuId());
        batchSaveMenuLang(shopMenu);
    }

    /**
     * 验证参数是否正确
     */
    private void verifyForm(ShopMenu shopMenu) {

        if (Objects.equals(shopMenu.getMenuId(), shopMenu.getParentId())) {
            // 自己不能是自己的上级
            throw new YamiShopBindException("yami.sys.menu.user.error");
        }
        if (shopMenu.getType() == MenuType.MENU.getValue()) {
            if (StrUtil.isBlank(shopMenu.getUrl())) {
                // 菜单URL不能为空
                throw new YamiShopBindException("yami.sys.menu.exist");
            }
        }
        if (!verifyLang(shopMenu)) {
            throw new YamiShopBindException("语言数据已更新，请重新录入商品信息");
        }

        //上级菜单类型
        int parentType = MenuType.CATALOG.getValue();
        if (shopMenu.getParentId() != 0) {
            ShopMenu parentMenu = getById(shopMenu.getParentId());
            parentType = parentMenu.getType();
        }

        //目录、菜单
        if (shopMenu.getType() == MenuType.CATALOG.getValue() || shopMenu.getType() == MenuType.MENU.getValue()) {
            if (parentType != MenuType.CATALOG.getValue()) {
                // // 上级菜单不为空时，只能为菜单类型
                throw new YamiShopBindException("yami.sys.menu.superior.list");
            }
            return;
        }

        //按钮
        if (shopMenu.getType() == MenuType.BUTTON.getValue()) {
            if ((parentType != 0) && parentType != MenuType.MENU.getValue()) {
                // 上级菜单不为空时，只能为菜单类型
                throw new YamiShopBindException("yami.sys.menu.superior.menu");
            }
        }
    }

    private boolean verifyLang(ShopMenu shopMenu) {
        boolean hasDefaultLang = false;
        if (CollUtil.isEmpty(shopMenu.getMenuLangList())) {
            return hasDefaultLang;
        }
        Integer defaultLang = langManager.getDefaultLang();
        for (ShopMenuLang shopMenuLang : shopMenu.getMenuLangList()) {
            if (Objects.equals(shopMenuLang.getLang(), defaultLang)) {
                hasDefaultLang = true;
            }
        }
        return hasDefaultLang;
    }

    private void handleMenuLang(List<ShopMenu> shopMenuList) {
        this.handleMenuAndLang(shopMenuList);
    }
    private void handleMenuAndLang(List<ShopMenu> shopMenuList) {
        if (CollUtil.isEmpty(shopMenuList)) {
            return;
        }
        Integer lang = I18nMessage.getLang();
        LangConfig langConfig = langManager.getLangConfig();
        for (ShopMenu shopMenu : shopMenuList) {
            if (CollUtil.isEmpty(shopMenu.getMenuLangList())) {
                continue;
            }
            Map<Integer, ShopMenuLang> menuLangMap = shopMenu.getMenuLangList().stream().collect(Collectors.toMap(ShopMenuLang::getLang, s -> s));
            ShopMenuLang shopMenuLang = menuLangMap.get(langManager.getLang(menuLangMap.keySet(), langConfig, lang));
            shopMenu.setName(shopMenuLang.getName());
        }
    }

    private void batchSaveMenuLang(ShopMenu shopMenu) {
        for (ShopMenuLang shopMenuLang : shopMenu.getMenuLangList()) {
            shopMenuLang.setMenuId(shopMenu.getMenuId());
        }
        shopMenuLangMapper.batchSave(shopMenu.getMenuLangList());
    }
}
